package com.credithc.eagleeye.plugins.thread;
import com.credithc.eagleeye.agent.factory.EagleEyeAgentFactory;
import com.credithc.eagleeye.agent.util.HostUtil;
import com.credithc.eagleeye.constants.RpcTypeEnum;
import com.credithc.eagleeye.exception.EagleEyeIgnoreException;
import com.credithc.eagleeye.plugins.util.LogUtil;
import com.credithc.eagleeye.thread.EagleEyeThreadContext;
import com.credithc.eagleeye.thread.TraceInfo;
import com.credithc.eagleeye.util.FastJsonConvert;
import com.credithc.eagleeye.util.ThrowableToStringArray;
import com.credithc.eagleeye.vo.RpcTraceInfoVo;
import org.slf4j.MDC;

import java.util.Date;

import static com.credithc.eagleeye.util.MixUtil.ISO_DATETIME_TIME_ZONE_FORMAT_WITH_MILLIS;
/**
 * 描 述: <br/>
 * 作 者: zhangjin<br/>
 * 创 建：2019年04月25日<br/>
 * 版 本：v1.0.0<br>
 * <p>
 * 历 史: (版本) 作者 时间 注释 <br/>
 */
public class EagleEyeRunnable implements Runnable {
    private final Runnable runnable;
    private TraceInfo traceInfo;
    private RpcTraceInfoVo rpcTraceInfoVo;
    public EagleEyeRunnable(Runnable runnable) {
        this.runnable = runnable;
        TraceInfo parentTraceInfo = EagleEyeThreadContext.getTraceInfo();
        if (parentTraceInfo != null) {
            //增加一个序号
            parentTraceInfo.addSequenceNo();
            this.traceInfo = new TraceInfo(parentTraceInfo.getTraceId(), parentTraceInfo.getRpcId(), parentTraceInfo.getUserInfo());
        }
    }
    @Override
    public void run() {
        initEagleEyeData();
        Exception exception = null;
        try {
            this.runnable.run();
        } catch (Exception ex) {
            exception = ex;
            throw ex;
        } finally {
            finishEagleEyeData(exception);
        }
    }
    private void initEagleEyeData() {
        if (traceInfo != null) {
            EagleEyeThreadContext.init();
            EagleEyeThreadContext.startWatch("runnable");
            rpcTraceInfoVo = new RpcTraceInfoVo();
            rpcTraceInfoVo.setRequestDateTime(ISO_DATETIME_TIME_ZONE_FORMAT_WITH_MILLIS.format(new Date()));
            rpcTraceInfoVo.setTraceId(traceInfo.getTraceId());
            rpcTraceInfoVo.setRpcId(traceInfo.getRpcId());
            rpcTraceInfoVo.setRpcType(RpcTypeEnum.THREAD.getRpcName());
            rpcTraceInfoVo.setServiceCategory("runnable");
            rpcTraceInfoVo.setServiceName(runnable.getClass().getSimpleName().length()==0?"Runnable":runnable.getClass().getSimpleName());
            rpcTraceInfoVo.setMethodName("run");
            rpcTraceInfoVo.setRequestJson(FastJsonConvert.convertObjectToJSON(runnable));
            rpcTraceInfoVo.setUserInfo(traceInfo.getUserInfo());
            rpcTraceInfoVo.setServerHost(HostUtil.getIp());
            rpcTraceInfoVo.setClientHost(HostUtil.getIp());
            traceInfo.addHierarchy();
            EagleEyeThreadContext.putTraceInfo(traceInfo);
            MDC.put("traceId", traceInfo.getTraceId());
            MDC.put("rpcId", traceInfo.getRpcId());
        }
    }
    /**
     * 发送鹰眼数据
     *
     * @param ex
     */
    private void finishEagleEyeData(Exception ex) {
        if (this.rpcTraceInfoVo != null) {
            try {
                rpcTraceInfoVo.setRunTime(EagleEyeThreadContext.stopWatch("runnable"));
                if (ex != null && !(ex instanceof EagleEyeIgnoreException)) {
                    //ERROR
                    rpcTraceInfoVo.setResult("ERROR");
                    //异常的结果
                    String[] traceStr = ThrowableToStringArray.convert(ex);
                    StringBuilder builder = new StringBuilder();
                    for(String trace : traceStr) {
                        builder.append(trace);
                        builder.append("\n");
                    }
                    rpcTraceInfoVo.setResponseJson(builder.toString());
                } else {
                    //OK
                    rpcTraceInfoVo.setResult("OK");
                }
                EagleEyeAgentFactory.getInstance().send2EagleEye(rpcTraceInfoVo);
                LogUtil.printSplunkLog(rpcTraceInfoVo);
            } catch (Exception e) {
            }finally {
                EagleEyeThreadContext.removeTraceInfo();
                MDC.remove("traceId");
                MDC.remove("rpcId");
            }
        }
    }
}
